{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ex4: Passivity Evaluation and Enforcement\n",
    "To demonstrate the passivity evaluation and enforcement features of the vector fitting class, the ring slot example 2-port is used, once again. Have a look at the other vector fitting example notebooks for more general explanations of the fitting process."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as mplt\n",
    "import numpy as np\n",
    "\n",
    "import skrf\n",
    "\n",
    "# load and fit the ring slot network with 3 poles\n",
    "nw = skrf.data.ring_slot\n",
    "vf = skrf.VectorFitting(nw)\n",
    "vf.vector_fit(n_poles_real=3, n_poles_cmplx=0)\n",
    "\n",
    "# plot fitting results\n",
    "freqs = np.linspace(0, 200e9, 201)\n",
    "fig, ax = mplt.subplots(2, 2)\n",
    "fig.set_size_inches(12, 8)\n",
    "vf.plot_s_mag(0, 0, freqs=freqs, ax=ax[0][0]) # s11\n",
    "vf.plot_s_mag(0, 1, freqs=freqs, ax=ax[0][1]) # s12\n",
    "vf.plot_s_mag(1, 0, freqs=freqs, ax=ax[1][0]) # s21\n",
    "vf.plot_s_mag(1, 1, freqs=freqs, ax=ax[1][1]) # s22\n",
    "fig.tight_layout()\n",
    "mplt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The fitting result looks fine, but a UserWarning about a non-passive vector fit was printed. Before investigating this issue, let's check the RMS error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vf.get_rms_error()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An RMS error of less than 0.05 usually indicates a good fit and confirms our optical inspection. But what about the passivity of the fitted model?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vf.is_passive()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Why is the model not passive? Wasn't the original data of the ring slot representing a passive network?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nw.is_passive()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The network data was passive, but the vector fitted model is not. Let's investigate (and correct?) the problem some more. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# plot singular values of vector fitted scattering matrix\n",
    "freqs = np.linspace(0, 200e9, 201)\n",
    "fig, ax = mplt.subplots(1, 1)\n",
    "fig.set_size_inches(6, 4)\n",
    "vf.plot_s_singular(freqs=freqs, ax=ax)\n",
    "fig.tight_layout()\n",
    "mplt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One of the singular values of the fitted scattering matrix is greater than 1 at some frequencies. This indeed indicates a non-passive model. For further analysis, you can get a list of all frequency bands with passivity violations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vf.passivity_test()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The network is not passive in two frequency bands: From dc to about 27.8 GHz, and from 84.3 GHz to 98.5 GHz.\n",
    "Luckily, passivity can be enforced to obtain passive vector fitted model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vf.passivity_enforce()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After passivity enforcement, the network should be passive at all frequencies. Let's check ourselves:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vf.is_passive()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vf.passivity_test()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# plot singular values of vector fitted scattering matrix\n",
    "freqs = np.linspace(0, 200e9, 201)\n",
    "fig, ax = mplt.subplots(1, 1)\n",
    "fig.set_size_inches(6, 4)\n",
    "vf.plot_s_singular(freqs=freqs, ax=ax)\n",
    "fig.tight_layout()\n",
    "mplt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alright, the model is finally passive. But does it still fit the original network data?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# plot fitting results again after passivity enforcement\n",
    "freqs = np.linspace(0, 200e9, 201)\n",
    "fig, ax = mplt.subplots(2, 2)\n",
    "fig.set_size_inches(12, 8)\n",
    "vf.plot_s_mag(0, 0, freqs=freqs, ax=ax[0][0]) # s11\n",
    "vf.plot_s_mag(0, 1, freqs=freqs, ax=ax[0][1]) # s12\n",
    "vf.plot_s_mag(1, 0, freqs=freqs, ax=ax[1][0]) # s21\n",
    "vf.plot_s_mag(1, 1, freqs=freqs, ax=ax[1][1]) # s22\n",
    "fig.tight_layout()\n",
    "mplt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition to the visual inspection, let's check the RMS error again:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vf.get_rms_error()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Yes, the model still fits the original data very well and the differences to the first non-passive fit from above are insignificant: the rms error is still very low."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
